package com.cl.code.generate.source.controller.entity;

import com.cl.code.generate.util.JavaCommentExtractor;
import lombok.Getter;
import org.springframework.web.bind.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * @author chengliang
 * @since 1.0.0
 */
@Getter
public class MethodMetadata {

    private final String methodName;

    private String path;

    private MethodType methodType;

    private String parameterType;

    private final List<ParamMetadata> paramList;

    private String returnType;

    private final String comment;

    public MethodMetadata(Method method, String basePath, Set<Class<?>> classCacheSet) {
        this.methodName = method.getName();

        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            switch (annotation) {
                case PostMapping postMapping -> {
                    this.methodType = MethodType.POST;
                    String[] value = postMapping.value();
                    if (value.length > 0) {
                        this.path = basePath + "/" + value[0];
                    }
                }
                case PutMapping putMapping -> {
                    this.methodType = MethodType.PUT;
                    String[] value = putMapping.value();
                    if (value.length > 0) {
                        this.path = basePath + "/" + value[0];
                    }
                }
                case GetMapping getMapping -> {
                    this.methodType = MethodType.GET;
                    String[] value = getMapping.value();
                    if (value.length > 0) {
                        this.path = basePath + "/" + value[0];
                    }
                }
                case DeleteMapping deleteMapping -> {
                    this.methodType = MethodType.DELETE;
                    String[] value = deleteMapping.value();
                    if (value.length > 0) {
                        this.path = basePath + "/" + value[0];
                    }
                }
                case PatchMapping patchMapping -> {
                    this.methodType = MethodType.PATCH;
                    String[] value = patchMapping.value();
                    if (value.length > 0) {
                        this.path = basePath + "/" + value[0];
                    }
                }
                case RequestMapping requestMapping -> {
                    RequestMethod requestMethod = requestMapping.method()[0];
                    switch (requestMethod) {
                        case GET -> this.methodType = MethodType.GET;
                        case HEAD -> this.methodType = MethodType.HEAD;
                        case POST -> this.methodType = MethodType.POST;
                        case PUT -> this.methodType = MethodType.PUT;
                        case PATCH -> this.methodType = MethodType.PATCH;
                        case DELETE -> this.methodType = MethodType.DELETE;
                        case OPTIONS -> this.methodType = MethodType.OPTIONS;
                        case TRACE -> this.methodType = MethodType.TRACE;
                    }
                    String[] value = requestMapping.value();
                    if (value.length > 0) {
                        this.path = basePath + "/" + value[0];
                    }
                }
                default -> {
                    // Ignore other annotations
                }
            }
        }
        if (this.methodType == null) {
            throw new NullPointerException("methodType is null");
        }
        // 处理请求参数
        Queue<Class<?>> queue = new LinkedList<>();
        for (Parameter parameter : method.getParameters()) {
            if (parameter.isAnnotationPresent(RequestBody.class)) {
                Class<?> type = parameter.getType();
                queue.add(parameter.getType());
                this.parameterType = type.getSimpleName();
            }
        }

        // 处理返回值
        Class<?> returnTypeClass = method.getReturnType();
        if (!returnTypeClass.equals(Void.TYPE)) {
            queue.add(returnTypeClass);
            this.returnType = returnTypeClass.getSimpleName();
        }

        List<ParamMetadata> paramList = new ArrayList<>(10);
        while (!queue.isEmpty()) {
            Class<?> clazz = queue.poll();
            if (classCacheSet.contains(clazz)) {
                continue;
            }
            classCacheSet.add(clazz);
            Field[] declaredFields = clazz.getDeclaredFields();
            List<FiledMetadata> filedList = new ArrayList<>(declaredFields.length);
            for (Field declaredField : clazz.getDeclaredFields()) {
                // 判断是否为java基本数据类型
                String tsFieldType;
                String fieldName = declaredField.getName();
                Class<?> javaFieldType = declaredField.getType();
                String javaFieldTypeName = javaFieldType.getName();
                if (JavaToTSMapper.containsJavaType(javaFieldTypeName)) {
                    tsFieldType = JavaToTSMapper.mapJavaTypeToTypeScript(javaFieldTypeName);
                } else {
                    if (!classCacheSet.contains(javaFieldType)) {
                        queue.add(javaFieldType);
                    }
                    tsFieldType = javaFieldType.getSimpleName();
                }
                // 这里可以根据需要处理参数类型
                FiledMetadata filedMetadata = new FiledMetadata(fieldName, tsFieldType, true);
                filedList.add(filedMetadata);
            }
            ParamMetadata paramMetadata = new ParamMetadata(clazz.getSimpleName(), filedList);
            paramList.add(paramMetadata);
        }
        this.paramList = paramList;


        this.comment = JavaCommentExtractor.extractMethodComment(method).getComment();
    }
}
